package com.shangma.cn.controller;

import com.shangma.cn.common.domin.LoginAdmin;
import com.shangma.cn.common.exception.ApiException;
import com.shangma.cn.common.http.AxiosResult;
import com.shangma.cn.common.http.AxiosStatus;
import com.shangma.cn.components.TokenService;
import com.shangma.cn.constants.RedisKey;
import com.shangma.cn.dto.MenuDTO;
import com.shangma.cn.entity.Admin;
import com.shangma.cn.entity.Menu;
import com.shangma.cn.service.AdminService;
import com.shangma.cn.service.MenuService;
import com.shangma.cn.service.RoleService;
import com.shangma.cn.transfer.MenuTransfer;
import com.shangma.cn.utils.TreeUtils;
import com.shangma.cn.utils.UploadService;
import com.wf.captcha.GifCaptcha;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.data.redis.core.StringRedisTemplate;
import org.springframework.security.crypto.bcrypt.BCryptPasswordEncoder;
import org.springframework.util.StringUtils;
import org.springframework.web.bind.annotation.*;
import org.springframework.web.context.request.RequestAttributes;
import org.springframework.web.context.request.RequestContextHolder;

import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpSession;
import javax.servlet.http.Part;
import java.io.IOException;
import java.util.*;
import java.util.stream.Collectors;

/**
 * 开发者：辉哥
 * 特点： 辉哥很帅
 * 开发时间：2021/6/23 9:46
 * 文件说明：
 */
@RestController
@RequestMapping("common")
public class CommonController {


    /**
     * 文件上传
     * <p>
     * <p>
     * 以前ssm整合  文件上传需要开启multipart  如果自己不限制文件上传大小 则随便上传
     * <p>
     * springBoot  文件上传默认开启multipart  默认的tomcat上传文件的大小为1M
     * 文件上传限制
     * 1： 格式限制    jpg  png
     * 2: 最多不能超过200K
     * 3: 宽高100*100
     * 4: 你必须给我上传个是图片
     * <p>
     * <p>
     * //     * ssm怎么用   redis
     * redis
     * jedis   lettuce
     * slf4j
     * <p>
     * 配置 RedisTempate
     * StringRedisTempate
     * <p>
     * 配置工程  设置连接池
     * <p>
     * <p>
     * <p>
     * 登录时 查询数据库 如果用户存在 密码匹配成功
     * <p>
     * 返回token  token中携带了信息 携带了缓存Redis中的用户的key
     */

    @Autowired
    private UploadService uploadService;

    @Autowired
    private AdminService adminService;

    @Autowired
    private BCryptPasswordEncoder bCryptPasswordEncoder;


    @Autowired
    private RoleService roleService;


    @Autowired
    private MenuService menuService;


    @Autowired
    private MenuTransfer menuTransfer;

    @Autowired
    private StringRedisTemplate stringRedisTemplate;

    @Autowired
    private TokenService tokenService;

    @PostMapping("upload")
    public AxiosResult<String> upload(@RequestPart Part avatar) throws IOException {
        return AxiosResult.success(uploadService.upload(avatar));
    }


    @GetMapping("getCode/{uuid}")
    public AxiosResult<String> getCode(@PathVariable String uuid) {
        // 使用gif验证码
        GifCaptcha gifCaptcha = new GifCaptcha(130, 48, 6);
        //图片中文字的值
        String text = gifCaptcha.text();
        stringRedisTemplate.opsForValue().set(RedisKey.CODE_KEY + uuid, text);
        String s = gifCaptcha.toBase64();
        return AxiosResult.success(s);
    }

    @PostMapping("doLogin")
    public AxiosResult<String> doLogin(@RequestBody Map<String, String> map) {

        String code = map.get("code");
        String uuid = map.get("uuid");
        String username = map.get("username");
        String password = map.get("password");
        String value = stringRedisTemplate.opsForValue().get(RedisKey.CODE_KEY + uuid);
        //判断验证码准确不准确
        if (StringUtils.isEmpty(value) || !value.equalsIgnoreCase(code))
            throw new ApiException(AxiosStatus.ERROE);
        Admin admin = adminService.getAdminByAccount(username);
        //账户名称不正确
        if (admin == null)
            throw new ApiException(AxiosStatus.ERROE);
        //比较密码
        if (!bCryptPasswordEncoder.matches(password, admin.getAdminPassword()))
            //密码错误
            throw new ApiException(AxiosStatus.ERROE);

        //清除Redis中的验证码数据
        stringRedisTemplate.delete(RedisKey.CODE_KEY + uuid);

        String token = tokenService.createTokenAndCacheLoginAdmin(admin);
        return AxiosResult.success(token);


        //返回用户的菜单  从用户 - 角色  -> 权限=》 过滤掉按钮级别的  并且封装Tree数据即可\

    }


    @GetMapping("getUserInfo")
    public AxiosResult<Map<String, Object>> getUserInfo(HttpServletRequest request) {

        LoginAdmin loginAdminCache = tokenService.getLoginAdminCache();
        System.out.println("登录用户为：" + loginAdminCache);
        Admin admin = loginAdminCache.getAdmin();
        System.out.println("admin：为" + loginAdminCache);
        Map<String, Object> map = new HashMap<>();

        map.put("admin", admin);
//        //超级管理员
        if (admin.getIsAdmin()) {
            //拿到所有权限
            List<Menu> list = menuService.list();
            //把用户所有权限放到LoginAdmin
            loginAdminCache.setMenus(list);
            List<MenuDTO> menuDTOS = menuTransfer.toDTO(list);
            List<MenuDTO> collect = menuDTOS.stream().filter(menuDTO -> !menuDTO.getMenuType().equals(3)).collect(Collectors.toList());
            List<MenuDTO> btnMenus = menuDTOS.stream().filter(menuDTO -> menuDTO.getMenuType().equals(3)).collect(Collectors.toList());
            List<MenuDTO> root = collect.stream().filter(menuDTO -> menuDTO.getParentId().equals(0L)).collect(Collectors.toList());
            TreeUtils.buildTreeData(root, collect);
            map.put("menuList", root);
            map.put("btnList",btnMenus);
            tokenService.setLoginAdminCache(loginAdminCache);
            return AxiosResult.success(map);
        } else {
            //从用户 - 角色
            List<Long> roleIds = adminService.getRolesByAdminId(admin.getId());
            //角色  -> 权限
            List<MenuDTO> list = roleService.getMenusByRoleIds(roleIds);
            List<Menu> menus = menuTransfer.toEntity(list);
            loginAdminCache.setMenus(menus);
            System.out.println("所有的权限为：" + list);
            List<MenuDTO> collect = list.stream().filter(menuDTO -> !menuDTO.getMenuType().equals(3)).collect(Collectors.toList());
            List<MenuDTO> btnMenus = list.stream().filter(menuDTO -> menuDTO.getMenuType().equals(3)).collect(Collectors.toList());
            System.out.println("菜单为：" + collect);
            List<MenuDTO> root = collect.stream().filter(menuDTO -> menuDTO.getParentId().equals(0L)).collect(Collectors.toList());
            TreeUtils.buildTreeData(root, collect);
            map.put("menuList", root);
            map.put("btnList", btnMenus);
            tokenService.setLoginAdminCache(loginAdminCache);
            return AxiosResult.success(map);
        }
    }


    /*
     * 以前的登录拦截是这样的
     *  1： 登录 登录成功之后 把用户信息存到session
     *  2: 定义拦截器  从session中获取登录信息
     *       如果能获取到证明 登录了
     *       如果获取不到 则证明没有登录
     * 问题：
     *
     *
     *   1： 前后端分离时 使用axios请求时 默认不携带cookie 所以每次访问的默认session都不一样  登录拦截失效
     *
     *   2： 解决方案： 携带cookie
     *
     *
     *   3： 实际开发中我们项目为了做到分流的效果 需要部署集群
     *       1个tomcat的并发量  默认值200  可以调整 最多调整到500左右 性能还行 如果调整的过高 性能就差了
     *
     *       所以在实际生产中： 要把项目部署多次  启动多个tomcat  占用不同的端口  使用nginx 做负载均衡
     *
     *       此时想要使用session做登录状态 此时需要共享session
     *
     *    session是有状态的
     *
     *
     * 思想
     *  4： 在登录成功时  给前端返回一个字符串   前端接收到这个字符串的时候 保存起来
     *  5： 前端每次请求 要在请求头中添加这个字符串  后台在拦截器中获取这个头部  看有没有传递过来 如果没有传递 证明没有登录 如果传递了 就证明登录了
     *
     *
     * 这个字符串 不能是明文  不能轻易让别人识别出来     =》token     JWT
     *
     *
     * Token是一个字符串  这个字符串中间有2个逗号 把这个字符串分割成了3部分
     *
     *
     *
     *
     *
     *
     * */

    @GetMapping("loginStatus")
    public String loginStatus(HttpSession httpSession) {
        RequestAttributes requestAttributes = RequestContextHolder.getRequestAttributes();
        System.out.println(requestAttributes.getClass().getName());


        return "success";
    }


}
